#include <stdio.h>
#include <opencv2/opencv.hpp>

class Ball
{
public:
    cv::Point center;
    int radius;
    cv::Point delta;

public:
    Ball(cv::Point _center, int _radius, cv::Point _delta):
        center(_center), radius(_radius), delta(_delta)
    {
    }
};

static
int get_random_int(int a, int b)
{
    if (a > b)
    {
        std::swap(a, b);
    }
    else if (a == b)
    {
        return a;
    }
    return (1.0 * rand() / RAND_MAX) * (b - a) + a;
}

static
void draw_ball(cv::Mat& image, Ball& ball)
{
    cv::Point& pt = ball.center;
    const int radius = ball.radius;
    cv::Scalar ball_color(0, 0, 0);
    const int thickness = -1;
    cv::circle(image, pt, radius, ball_color, thickness);
}

static
void update(cv::Mat& image, const cv::Scalar& bg_color, Ball& ball)
{
    image = bg_color;

    draw_ball(image, ball);

    cv::Point& ct = ball.center;
    cv::Point& delta = ball.delta;
    int radius = ball.radius;
    
    cv::Point new_ct;

    new_ct.x = ct.x + delta.x * radius;
    new_ct.y = ct.y + delta.y * radius;

    const int h = image.rows;
    const int w = image.cols;

    if (new_ct.y < 0 || new_ct.y >= h)
    {
        delta.y *= -1;
    }
    if (new_ct.x < 0 || new_ct.x >= w)
    {
        delta.x *= -1;
    }

    ct.x = ct.x + delta.x * radius;
    ct.y = ct.y + delta.y * radius;
}

int main()
{
    const int w = 640;
    const int h = 480;
    cv::Size size(w, h);
    cv::Mat image(size, CV_8UC3);
    cv::Scalar bg_color = cv::Scalar(255, 255, 255, 255);
    image = bg_color;

    int x;
    int y;
    x = get_random_int(0, w);
    y = get_random_int(0, h);
    cv::Point ball_center(x, y);

    int radius = 20;
    cv::Point delta(1, 1);
    Ball ball(ball_center, radius, delta);

    while (true)
    {
        update(image, bg_color, ball);

        cv::imshow("image", image);
        cv::waitKey(200);
    }

    return 0;
}

